﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using OSMLib;

namespace MapSurface
{
    public class RenderMapArtifacts
    {
        readonly ISurface _surface;
        public RenderMapArtifacts(ISurface surface)
        {
            _surface = surface;
        }

        void DoOsmPlotLaosBoundary()
        {
            int nationalSize = 2;

            if (_surface.XScale >= 1000)
                nationalSize = 4;

            foreach (OsmWay w in Osm.Ways.Values)
            {
                if (_surface.WayVisible(w) && w.IsBoundary && w.IsNationalBoundary && w.IsLaosBoundary)
                {
                    AddPolyline(w, Brushes.Black, nationalSize);
                }
            }
        }
        public void AddToCanvas()
        {
           // DoOsmPlotLaosBoundary();
            
            var railway = new List<OsmWay>();
            var nationalPark = new List<OsmWay>();
            var naturalWood = new List<OsmWay>();
            var waterway = new List<OsmWay>();
            var naturalWater = new List<OsmWay>();
            var naturalLand = new List<OsmWay>();
            var boundary = new List<OsmWay>();
            var landuseResidential = new List<OsmWay>();
            var leisureGarden = new List<OsmWay>();
            var building = new List<OsmWay>();
            var aeroway = new List<OsmWay>();
            var ferry = new List<OsmWay>();

            foreach (OsmWay w in Osm.Ways.Values)
            {
                if (_surface.WayVisible(w))
                {
                    if (w.IsRailway)
                    {
                        railway.Add(w);
                        continue;
                    }

                    if (w.IsNaturalWater)
                    {
                        naturalWater.Add(w);
                        continue; // Natural water trumps waterway
                    }

                    if (w.IsWaterway)
                    {
                        waterway.Add(w);
                        continue;
                    }

                    if (w.IsBoundary)
                    {
                        boundary.Add(w);
                        continue;
                    }

                    if (w.IsAeroway)
                    {
                        aeroway.Add(w);
                        continue;
                    }

                    if (w.IsFerry)
                    {
                        ferry.Add(w);
                        continue;
                    }

                    if (_surface.XScale >= 25)
                    {
                        if (w.IsNationalPark)
                        {
                            nationalPark.Add(w);
                            continue;
                        }
                    }

                    if (_surface.XScale >= 250)
                    {
                        if (w.IsNaturalWood)
                        {
                            naturalWood.Add(w);
                            continue;
                        }
                    }

                    if (_surface.XScale >= 1000)
                    {
                        if (w.IsNaturalLand)
                        {
                            naturalLand.Add(w);
                            continue;
                        }
                    }

                    if (_surface.XScale >= 10000)
                    {
                        if (w.IsLanduseResidential)
                        {
                            landuseResidential.Add(w);
                            continue;
                        }

                        if (w.IsLeisureGarden)
                        {
                            leisureGarden.Add(w);
                            continue;
                        }

                        if (w.IsBuilding)
                        {
                            building.Add(w);
                            continue;
                        }
                    }
                }
            }
         
            AddPolygonLayer(nationalPark, Brushes.LightGreen);
            AddPolygonLayer(naturalWood, Brushes.DarkGreen);
            DoOsmPlotWaterway(waterway); // rivers
            AddPolygonLayer(naturalWater, Brushes.LightBlue);
            AddPolygonLayer(naturalLand, Brushes.LightYellow);
            //  DoOsmPlotCommunityNames();
            DoOsmPlotBoundary(boundary);
            AddPolygonLayer(landuseResidential, Brushes.LightGray);
            AddPolygonLayer(leisureGarden, Brushes.LightYellow);
            AddPolygonLayer(building, Brushes.LightPink);
            DoOsmPlotAeroway(aeroway);
            DoOsmPlotFerry(ferry);
            DoOsmPlotRailway(railway);
        }
        
        void DoOsmPlotRailway(IEnumerable<OsmWay> ways)
        {
            foreach (OsmWay w in ways)
            {
                if (w.IsHighWayVisible(_surface.XScale))
                {
                    double size = 6;
                    if (_surface.XScale <= 1000)
                        size /= 2;

                    if (_surface.XScale <= 100)
                        size /= 2;

                    if (size < 1)
                        size = 1;

                    AddPolyline(w, Brushes.Gray, size);
                }
            }
        }

        void DoOsmPlotFerry(IEnumerable<OsmWay> ways)
        {
            foreach (var w in ways)
            {
                if (w.IsHighWayVisible(_surface.XScale))
                {
                    double size = 2;
                    if (_surface.XScale <= 1000)
                        size /= 2;

                    if (size < 1)
                        size = 1;

                    AddPolyline(w, Brushes.Brown, size);
                }
            }
        }

        void DoOsmPlotAeroway(IEnumerable<OsmWay> ways)
        {
            foreach (OsmWay w in ways)
            {
                if (w.IsHighWayVisible(_surface.XScale))
                {
                    double size = 6;
                    if (_surface.XScale <= 1000)
                        size /= 2;

                    if (_surface.XScale <= 100)
                        size /= 2;

                    if (size < 1)
                        size = 1;

                    AddPolyline(w, Brushes.DarkGray, size);
                }
            }
        }

        private void AddPolygonLayer(IEnumerable<OsmWay> ways, SolidColorBrush b)
        {
            foreach (OsmWay w in ways)
            {
                AddPolygon(w, b);
            }
        }

        void DoOsmPlotBoundary(IEnumerable<OsmWay> ways)
        {
            int nationalSize = 2;

            if (_surface.XScale >= 1000)
                nationalSize = 4;

            foreach (OsmWay w in ways)
            {

                if (w.IsNationalBoundary)
                {
                    if (w.IsLaosBoundary)
                    {
                        AddPolyline(w, Brushes.Purple, nationalSize);
                    }
                }
                else
                {
                    AddPolyline(w, Brushes.Purple, 1);
                }
            }
        }

        void DoOsmPlotCommunityNames()
        {
            foreach (OsmNode w in Osm.NamedNodes)
            {
                if (_surface.NodeVisible(w))
                {
                    PlaceCommunityBlobNode(w);
                }
            }
        }

        private void PlaceCommunityBlobNode(OsmNode n)
        {
            if (!n.IsPlace)
                return;

            if (!_surface.NodeVisible(n))
                return;

            double px = _surface.GetPx(n._wgs.Longitude);
            double py = _surface.GetPy(n._wgs.Latitude);

            var br = new SolidColorBrush(Colors.DarkGray) {Opacity = 0.5};

            double size = 8;

            if (n.IsCity)
                size = 20;


            if (_surface.XScale >= 1000)
            {
                size *= 2;
            }

            if (_surface.XScale >= 10000)
            {
                size *= 2;
            }

            if (_surface.XScale >= 50000)
            {
                size *= 2;
            }

            if (_surface.XScale >= 100000)
            {
                size *= 2;
            }

            if (_surface.XScale >= 500000)
            {
                size *= 2;
            }

            if (_surface.XScale >= 1000000)
            {
                size *= 2;
            }

            var el = new Ellipse { Height = size, Width = size, Tag = n, StrokeThickness = 0, Fill = br };
            el.StrokeThickness = 1;
            el.Stroke = Brushes.Black;

            Canvas.SetLeft(el, px - size / 2);
            Canvas.SetTop(el, py - size / 2);
            _surface.TheCanvas.Children.Add(el);
        }

  
        void DoOsmPlotWaterway(IEnumerable<OsmWay> ways)
        {
            int size = 1;

            if (_surface.XScale >= 1000)
                size = 2;

            if (_surface.XScale >= 1000)
                size = 4;

            foreach (OsmWay w in ways)
            {
                AddPolyline(w, Brushes.Blue, size);
            }
        }

        private void AddPolyline(OsmWay way, SolidColorBrush br, double size)
        {
            var polly = new Polyline
                            {
                                StrokeThickness = size,
                                Stroke = br,
                                Points = new PointCollection(),
                                StrokeStartLineCap = PenLineCap.Round,
                                StrokeEndLineCap = PenLineCap.Round,
                                StrokeLineJoin = PenLineJoin.Round,
                                Tag = way
                            };

            foreach (OsmNode n1 in way.Nodes)
            {
                double px = _surface.GetPx(n1._wgs.Longitude);
                double py = _surface.GetPy(n1._wgs.Latitude);
                polly.Points.Add(new Point(px, py));
            }

            if (polly.Points.Count != 0)
                _surface.TheCanvas.Children.Add(polly);
        }

        private void AddPolygon(OsmWay n, SolidColorBrush br)
        {
            var polly = new Polyline
                            {
                                StrokeThickness = 0,
                                Fill = br,
                                Points = new PointCollection(),
                                StrokeStartLineCap = PenLineCap.Round,
                                StrokeEndLineCap = PenLineCap.Round,
                                StrokeLineJoin = PenLineJoin.Round,
                                Tag = n
                            };

            foreach (OsmNode n1 in n.Nodes)
            {
                double px = _surface.GetPx(n1._wgs.Longitude);
                double py = _surface.GetPy(n1._wgs.Latitude);
                polly.Points.Add(new Point(px, py));
            }

            if (polly.Points.Count != 0)
                _surface.TheCanvas.Children.Add(polly);
        }
    }
}
